# -*- coding: utf-8 -*-
import sys
import os
import logging
import stat
from time import time, asctime, gmtime, mktime
from datetime import datetime, timedelta
from mimetypes import guess_type
from random import randint
from cStringIO import StringIO
from os.path import dirname, abspath, join
from hashlib import md5
############################################################################
from werkzeug.exceptions import NotFound, MethodNotAllowed
from werkzeug.wrappers import Response
from werkzeug.utils import get_content_type
from werkzeug.http import generate_etag
############################################################################


class Handler(object):
    rule = None
    request = None
    def __call__(self, kwargs):
        self.kwargs = kwargs
        if self.request.method == 'GET':
            return self.get()
        elif self.request.method == 'POST':
            return self.post()
        elif self.request.method == 'HEAD':
            return self.head()
        elif self.request.method == 'OPTIONS':
            return self.options()
        elif self.request.method == 'PUT':
            return self.put()
        elif self.request.method == 'DELETE':
            return self.delete()
        elif self.request.method == 'TRACE':
            return self.trace()
        else:
            raise MethodNotAllowed

    def get(self):
        raise MethodNotAllowed

    def post(self):
        raise MethodNotAllowed

    def head(self):
        raise MethodNotAllowed

    def options(self):
        raise MethodNotAllowed

    def put(self):
        raise MethodNotAllowed

    def delete(self):
        raise MethodNotAllowed

    def trace(self):
        raise MethodNotAllowed

    @classmethod
    def getLogger(cls):
        return logging.getLogger(cls.__name__)

    @property
    def logger(self):
        return self.getLogger()


class StaticHandler(Handler):
    def get(self):
        path = self.kwargs.get('path')
        if path is None:
            filename = self.static_file
        else:
            filename = os.path.join(self.static_dir, path)
        if not os.path.isfile(filename):
            raise NotFound
        type, encoding = guess_type(filename)
        type = type or 'application/octet-stream'
        real_mtime = os.stat(filename)[stat.ST_MTIME]
        if self.request.if_modified_since:
            ask_mtime = int(mktime(self.request.if_modified_since.timetuple()))
            if ask_mtime >= real_mtime:
                return Response(status=304)
        response = Response(mimetype=type)
        now = datetime.now()
        response.last_modified = datetime.fromtimestamp(real_mtime)
        response.expires = now + timedelta(seconds=3600)
        response.cache_control.max_age = 3600
        response.response = open(filename, 'rb')
        return response


class XMLRPCException(Exception):
    def __init__(self, code, message):
        self.code = code
        Exception.__init__(self, message)


class XMLRPC(Handler):
    def get(self):
        from jinja2 import Template
        functions = [getattr(self, fname) for fname in dir(self)
                if fname.startswith('rpc_')
        ]
        functions = [{
            'name': f.__name__[4:],
            'doc': f.im_func.func_doc,
            'varnames': '<br />'.join(f.im_func.func_code.co_varnames[1:]),
        } for f in functions]
        return Response(Template(u"""
        <table border="1">
            <tr><th>函数名称</th><th>参数</th><th>文档</th></tr>
            {% for f in functions %}
            <tr><td>{{ f.name|e }}</td><td>{{ f.varnames }}</td><td>{{ f.doc|e }}</td></tr>
            {% endfor %}
        </table>
        """).render(functions=functions))

    def post(self):
        import xmlrpclib
        try:
            try:
                p, m = xmlrpclib.loads(self.request.data)
            except:
                raise XMLRPCException(-32400, "system error: Request Invalid")

            f = getattr(self, 'rpc_'+m, None)
            if f is None:
                raise XMLRPCException(-32400, "system error: Cannot find method %s" % m)
            try:
                result = f(*p)
            except Exception, e:
                self.logger.error(e)
                raise XMLRPCException(-32400, "system error: %s" % e)
            else:
                xml = xmlrpclib.dumps((result,), methodresponse=1)
        except XMLRPCException, e:
            xml = xmlrpclib.dumps(xmlrpclib.Fault(e.code, e.message), methodresponse=1)
        response = Response(xml, content_type='text/xml')
        response.headers['Content-Length'] = len(xml)
        return response


class JSONRPCException(Exception):
    def __init__(self, name, message):
        self.name = name
        Exception.__init__(self, message)


class JSONRPC(Handler):
    def post(self):
        self.request.environ["CONTENT_TYPE"] = "application/json"
        from simplejson import loads, dumps
        id_ = ''
        result = None
        try:
            try:
                req = loads(self.request.data)
            except ValueError, e:
                raise JSONRPCException("JSONDecodeError", self.request.data)

            try:
                id_ = req["id"]
                method_name = req["method"]
                params = req["params"]
            except:
                raise JSONRPCException("BadServiceRequest", req)

            method = getattr(self, "rpc_"+method_name, None)
            if method is None:
                raise JSONRPCException("ServiceMethodNotFound", method)

            try:
                result = method(*params)
            except Exception, e:
                raise JSONRPCException(e.__class__.__name__, str(e))

        except JSONRPCException, e:
            err = {"name": e.name, "message": e.message}
            data = dumps({"result": None, "id": id_, "error": err})
        else:
            data = dumps({"result": result, "id": id_, "error": None})
        response = Response(data, content_type="application/json")
        response.headers['Content-Length'] = len(data)
        return response


class AuthenticateHandler(Handler):
    realm = "My Protection"
    users = {"admin": "123456"}
    def __call__(self, kwargs):
        auth = self.request.authorization
        if auth and self.users.get(auth.username) == auth.password:
            return Handler.__call__(self, kwargs)
        response = Response('Restricted Access', 401)
        response.headers['WWW-Authenticate'] = 'Basic realm="%s"'%(self.realm,)
        return response


_current_path = abspath(dirname(__file__))
class CaptchaHandler(Handler):
    def get(self):
        import captchaimage
        import Image, ImageDraw
        #text = md5(str(datetime.now())).hexdigest()[:4]
        text = "%04d"%randint(0, 9999)
        self.request.client_session["checkcode"] = text.lower()
        size_x = 30
        size_y = 40
        image_data = captchaimage.create_image(
            join(_current_path, "roughage.ttf"), size_x, size_y, text
        )
        image = Image.fromstring(
                "L", (len(image_data) / size_y, size_y), image_data
        )
        #draw = ImageDraw.Draw(image)
        #linecolor = (0,0,0)
        #for i in range(3):
        #    x1 = randint(0, size_x*4)
        #    x2 = randint(0, size_x*4)
        #    y1 = randint(0, size_y)
        #    y2 = randint(0, size_y)
        #    draw.line([(x1, y1), (x2, y2)])
        #del draw
        buf = StringIO()
        image.save(buf, "jpeg")
        return Response(buf.getvalue(), mimetype="image/jpeg",
                headers=[('Expires', '0'), ('Pragma', 'no-cache')])
